package tools

import (
	"encoding/base64"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
)

// ReadFile 读取文件内容
func ReadFile(filePath string) (string, error) {
	// 开始读取文件

	// 安全路径验证
	if err := validateFilePath(filePath); err != nil {
		return "", fmt.Errorf("文件路径不安全: %v", err)
	}

	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		return "", fmt.Errorf("文件不存在: %s", filePath)
	}

	// 检查文件扩展名，决定处理方式
	ext := strings.ToLower(filepath.Ext(filePath))

	// 多媒体文件处理
	if isMultimediaFile(ext) {
		content, err := readMultimediaFile(filePath)
		if err != nil {
			return "", fmt.Errorf("读取多媒体文件失败: %v", err)
		}
		return content, nil
	}

	// 文本文件处理
	content, err := readTextFile(filePath)
	if err != nil {
		return "", fmt.Errorf("读取文本文件失败: %v", err)
	}
	return content, nil
}

// ReplaceInFile 替换文件中的字符串
func ReplaceInFile(filePath, oldStr, newStr string) error {
	// 开始替换文件内容

	// 安全路径验证
	if err := validateFilePath(filePath); err != nil {
		return fmt.Errorf("文件路径不安全: %v", err)
	}

	// 验证字符串替换安全性
	if err := validateStringReplacement(oldStr, newStr); err != nil {
		return fmt.Errorf("字符串替换不安全: %v", err)
	}

	// 清理输入
	oldStr = sanitizeInput(oldStr)
	newStr = sanitizeInput(newStr)

	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		return fmt.Errorf("文件不存在: %s", filePath)
	}

	// 读取文件内容
	content, err := os.ReadFile(filePath)
	if err != nil {
		return fmt.Errorf("读取文件失败: %v", err)
	}

	// 检查旧字符串是否存在
	if !strings.Contains(string(content), oldStr) {
		return fmt.Errorf("文件中未找到指定的字符串")
	}

	// 替换字符串
	newContent := strings.ReplaceAll(string(content), oldStr, newStr)

	// 写回文件
	err = os.WriteFile(filePath, []byte(newContent), 0644)
	if err != nil {
		return fmt.Errorf("写入文件失败: %v", err)
	}
	return nil
}

// readTextFile 读取文本文件
func readTextFile(filePath string) (string, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	content, err := io.ReadAll(file)
	if err != nil {
		return "", err
	}

	return string(content), nil
}

// readMultimediaFile 读取多媒体文件并转换为Base64
func readMultimediaFile(filePath string) (string, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	content, err := io.ReadAll(file)
	if err != nil {
		return "", err
	}

	// 转换为Base64
	base64Content := base64.StdEncoding.EncodeToString(content)
	return base64Content, nil
}

// isMultimediaFile 判断是否为多媒体文件
func isMultimediaFile(ext string) bool {
	multimediaExts := []string{".png", ".jpg", ".jpeg", ".gif", ".bmp", ".pdf"}
	for _, multimediaExt := range multimediaExts {
		if ext == multimediaExt {
			return true
		}
	}
	return false
}

// FileExists 检查文件是否存在
func FileExists(filePath string) bool {
	_, err := os.Stat(filePath)
	return !os.IsNotExist(err)
}

// IsDirectory 检查是否为目录
func IsDirectory(path string) bool {
	info, err := os.Stat(path)
	if err != nil {
		return false
	}
	return info.IsDir()
}

// GetFileInfo 获取文件信息
func GetFileInfo(filePath string) (os.FileInfo, error) {
	// 安全路径验证
	if err := validateFilePath(filePath); err != nil {
		return nil, fmt.Errorf("文件路径不安全: %v", err)
	}

	return os.Stat(filePath)
}

// ListFiles 列出目录中的文件
func ListFiles(dirPath string) ([]string, error) {
	// 安全路径验证
	if err := validateFilePath(dirPath); err != nil {
		return nil, fmt.Errorf("目录路径不安全: %v", err)
	}

	files, err := os.ReadDir(dirPath)
	if err != nil {
		return nil, err
	}

	var fileNames []string
	for _, file := range files {
		fileNames = append(fileNames, file.Name())
	}

	return fileNames, nil
}

// validateFilePath 验证文件路径安全性
func validateFilePath(filePath string) error {
	if filePath == "" {
		return fmt.Errorf("文件路径为空")
	}

	// 使用filepath.Clean清理路径
	cleanPath := filepath.Clean(filePath)

	// 检查是否包含危险字符
	dangerousChars := []string{"..", "\\", "\x00"}
	for _, char := range dangerousChars {
		if strings.Contains(cleanPath, char) {
			return fmt.Errorf("路径包含危险字符: %s", char)
		}
	}

	// 获取绝对路径
	absPath, err := filepath.Abs(cleanPath)
	if err != nil {
		return fmt.Errorf("无法获取绝对路径: %v", err)
	}

	// 获取当前工作目录
	wd, err := os.Getwd()
	if err != nil {
		return fmt.Errorf("无法获取工作目录: %v", err)
	}

	// 检查是否在工作目录内（防止目录遍历攻击）
	wdAbs, err := filepath.Abs(wd)
	if err != nil {
		return fmt.Errorf("无法获取工作目录绝对路径: %v", err)
	}

	// 只允许访问工作目录及其子目录
	if !strings.HasPrefix(absPath, wdAbs) {
		return fmt.Errorf("禁止访问工作目录外的文件: %s", absPath)
	}

	// 检查文件大小限制（对于读取操作）
	if info, err := os.Stat(absPath); err == nil {
		const maxFileSize = 50 * 1024 * 1024 // 50MB
		if info.Size() > maxFileSize {
			return fmt.Errorf("文件过大: %d bytes (最大允许: %d bytes)", info.Size(), maxFileSize)
		}
	}

	return nil
}

// sanitizeInput 清理用户输入，防止注入攻击
func sanitizeInput(input string) string {
	// 移除或转义危险字符
	input = strings.ReplaceAll(input, "\n", "")
	input = strings.ReplaceAll(input, "\r", "")
	input = strings.ReplaceAll(input, "\t", " ")

	// 限制输入长度
	const maxInputLength = 1000
	if len(input) > maxInputLength {
		input = input[:maxInputLength] + "..."
	}

	return strings.TrimSpace(input)
}

// validateStringReplacement 验证字符串替换的安全性
func validateStringReplacement(oldStr, newStr string) error {
	if oldStr == "" {
		return fmt.Errorf("要替换的字符串不能为空")
	}

	// 检查字符串长度
	if len(oldStr) > 10000 || len(newStr) > 10000 {
		return fmt.Errorf("字符串过长")
	}

	// 检查是否包含危险字符
	dangerousPatterns := []string{"\x00", "\r\n\r\n"}
	for _, pattern := range dangerousPatterns {
		if strings.Contains(newStr, pattern) {
			return fmt.Errorf("替换字符串包含危险模式")
		}
	}

	return nil
}
